JS 规范
JS 规范
缩进
使用 tab 缩进(2 个空格)
if (x < y) {
x += 10;
} else {
x += 1;
}
变量声明
一个函数作用域中所有的变量声明尽量提到函数首部。优先使用块级变量let 和 const,如无需修改的常量使用const
单行长度
单行长度不得超过 100,超过部分需要换行
分号
统一要加分号。
空格
- 三元运算符'?:'前后
- 逗号后必须要有空格
- 代码块'{'前
- 下列关键字前:else, while, catch, finally
- 下列关键字后:if, else, for, while, do, switch, case, try,catch, finally, with, return, typeof
- 单行注释'//'后(若单行注释和代码同行,则'//'前也需要),多行注释'*'后
- 对象的属性值前
- for 循环,分号后留有一个空格,前置条件如果有多个,逗号后留一个空格
- 无论是函数声明还是函数表达式,'{'前一定要有空格
- 函数的参数之间
例:
// not good
var a = {
b: 1,
};
// good
var a = {
b: 1,
};
// not good
++x;
y++;
z = x ? 1 : 2;
// good
++x;
y++;
z = x ? 1 : 2;
// not good
var a = [1, 2];
// good
var a = [1, 2];
// good
var doSomething = function(a, b, c) {
// do something
};
// good
doSomething(item);
// not good
for (let i = 0; i < 6; i++) {
x++;
}
// good
for (let i = 0; i < 6; i++) {
x++;
}
命名
普命名
普通命名采用小驼峰式命名
let userName = "jack";
复数命名
命名是复数的时候需要加 s,比如说我想声明一个数组,表示很多人的名字
let names = new Array();
常量命名
每个常量都需命名,这样更利于别人读懂含义
// good
const COL_NUM = 10;
let row = Math.ceil(num / COL_NUM);
// bad
let row = Math.ceil(num / 10);
类命名
类命名一律采用PascalCase命名风格
class Test {}
语义化
命名需要符合语义化,如果函数命名,可以采用加上动词前缀:
- can 判断是否可执行某个动作
- has 判断是否含有某个值
- is 判断是否为某个值
- get 获取某个值
- set 设置某个值
//是否可阅读
function canRead(){
return true;
}
//获取姓名
function getName{
return this.name
}
注释
单行注释
- 注释单独一行的情况下,注释的//后面要跟一个空格
- 一律在被注释对象上方进行注释
// good
// 调用函数
foo();
// bad
let maxCount = 10; //这是一个变量
多行注释
多行注释建议在以下几种情况使用:
- 难于理解的代码段
- 可能存在错误的代码段
- 业务逻辑强相关的代码
/** 类描述 */
export default class Test {
/** 成员变量描述 */
testValue = true;
/** 方法描述
* @param {String} a 参数描述
* @return {Number} 返回值描述
*/
test(a) {
return this.testValue;
}
}
复杂度
不允许存在多层嵌套的条件判断和循环(最多三层)(重点强调 ⭐) 条件判断能使用三目运算符和逻辑运算符解决的,就不要使用条件判断,但是谨记不要写太长的三目运算符。
// bad
if (x === 10) {
return "valid";
} else {
return "invalid";
}
// good
return x === 10 ? "valid" : "invalid";
// bad
if (!x) {
if (!y) {
x = 1;
} else {
x = y;
}
}
// good
x = x || y || 1;
字符串
统一使用单引号而不是双引号
// bad
const name = "jack";
// good
const name = "jack";
用字符串模板而不是 '+' 来拼接字符串
// bad
function sayHi(name) {
return "How are you, " + name + "?";
}
// good
function sayHi(name) {
return `How are you, ${name}?`;
}
数组
用字面量赋值
// bad
const items = new Array();
// good
const items = [];
用扩展运算符做数组浅拷贝
// bad
let arr = [1, 2, 3];
const len = arr.length;
const copyArr = [];
for (let i = 0; i < len; i += 1) {
copyArr[i] = arr[i];
}
// good
const copyArr = [...arr];
用 Array.from 去将一个类数组对象转成一个数组。
const arrLike = { 0: "foo", 1: "bar", 2: "baz", length: 3 };
// bad
const arr = Array.prototype.slice.call(arrLike);
// good
const arr = Array.from(arrLike);
使用数组解构
const arr = [1, 2, 3, 4];
// bad
const first = arr[0];
const second = arr[1];
// good
const [first, second] = arr;
对象
创建对象和数组推荐使用字面量,因为这不仅是性能最优也有助于节省代码量。
// good
let obj = {
name: "Tom",
age: 15,
sex: "男",
};
// bad
let obj = {};
obj.name = "Tom";
obj.age = 15;
obj.sex = "男";
ES6 使用属性值缩写
const lukeSkywalker = "Luke Skywalker";
// bad
const obj = {
lukeSkywalker: lukeSkywalker,
};
// good
const obj = {
lukeSkywalker,
};
将属性的缩写放在对象声明的开头
const anakinSkywalker = "Anakin Skywalker";
const lukeSkywalker = "Luke Skywalker";
// bad
const obj = {
episodeOne: 1,
twoJediWalkIntoACantina: 2,
lukeSkywalker,
episodeThree: 3,
mayTheFourth: 4,
anakinSkywalker,
};
// good
const obj = {
lukeSkywalker,
anakinSkywalker,
episodeOne: 1,
twoJediWalkIntoACantina: 2,
episodeThree: 3,
mayTheFourth: 4,
};
对象浅拷贝时,更推荐使用扩展运算符 ...,而不是 Object.assign。解构赋值获取对象指定的几个属性时,推荐用 rest 运算符,也是 ...。
// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 });
delete copy.a; // 改变了 original
// bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
// good
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
函数
函数参数使用默认值替代使用条件语句进行赋值。
// good
function createMicrobrewery(name = 'Jack') {
...
}
// bad
function createMicrobrewery(name) {
const userNameName = name || 'Jack'
...
}
复制代码
函数参数使用结构语法,函数参数越少越好,如果参数超过两个,要使用 ES6 的解构语法,不用考虑参数的顺序。
// good
function createMenu({ title, body, buttonText, cancellable }) {
...
}
createMenu({
title: 'Foo',
body: 'Bar',
buttonText: 'Baz',
cancellable: true,
})
// bad
function createMenu(title, body, buttonText, cancellable) {
// ...
}
优先使用 rest 语法...,而不是 arguments
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join("");
}
// good
function concatenateAll(...args) {
return args.join("");
}
把默认参数赋值放在最后
// bad
function handleThings(opts = {}, name) {
// ...
}
// good
function handleThings(name, opts = {}) {
// ...
}
尽量使用箭头函数
// bad
[1, 2, 3]
.map(function(x) {
const y = x + 1;
return x * y;
})
[
// good
(1, 2, 3)
].map((x) => {
const y = x + 1;
return x * y;
});
模块
在非标准模块系统上使用(import/export)
// bad
const AirbnbStyleGuide = require("./AirbnbStyleGuide");
module.exports = AirbnbStyleGuide.es6;
// ok
import AirbnbStyleGuide from "./AirbnbStyleGuide";
export default AirbnbStyleGuide.es6;
// best
import { es6 } from "./AirbnbStyleGuide";
export default es6;
一个入口只 import 一次
// bad
import foo from "foo";
// … some other imports … //
import { named1, named2 } from "foo";
// good
import foo, { named1, named2 } from "foo";
在只有一个导出的模块里,用 export default 更好
// bad
export function foo() {}
// good
export default function foo() {
Powered by Waline v2.15.8